前幾天有提到 SvelteKit 是一個全端框架,也就是說它能夠寫一些簡單的 API ,關於 API 的路由控制也跟我們的頁面一樣都是跟資料夾的結構相關聯的。
在 SvelteKit 中是用 +server.ts
來做為 API 路由的檔案,寫法上跟 +page.ts
和 +layout.ts
類似都是 export
一個特定名稱的 function
//in src/routes/api/random-number/+server.ts
import { error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
export const GET: RequestHandler = ({ url }) => {
const min = Number(url.searchParams.get('min') ?? '0');
const max = Number(url.searchParams.get('max') ?? '1');
const d = max - min;
if (isNaN(d) || d < 0) {
error(400, 'min and max must be numbers, and min must be less than max');
}
const random = min + Math.random() * d;
return new Response(String(random));
};
除了 GET
還能使用 POST
、 PATCH
、 PUT
、 DELETE
、OPTIONS
和 HEAD
這些常見的 HTTP 的 request method 。
接下來我們就可以直接到 http://localhost:5173/api/random-number
看一下能否成功打 API 。
傳入 params http://localhost:5173/api/random-number?min=1&max=3
如果我們刻意的讓它觸發錯誤也能夠成功顯示錯誤頁面
要在 Svelte component 中使用它的話也很簡單,只需要跟平常打 API 一樣 fetch(/api/random-number)
就可以了。
<!-- in src/routes/day18/+page.svelte -->
<script lang="ts">
let min = $state(0);
let max = $state(100);
const getRandomNumber = async ({ min, max }: { min: number; max: number }): Promise<number> => {
return fetch(`/api/random-number?min=${min}&max=${max}`).then((x) => x.json());
};
</script>
<h1>Day18</h1>
<div class="flex gap-6 w-1/2">
<label for="min">
Min: {min}
<input type="range" min="0" max="100" bind:value={min} class="range" />
</label>
<label for="max">
Max: {max}
<input type="range" min="0" max="100" bind:value={max} class="range" />
</label>
</div>
{#await getRandomNumber({ min, max }) then number}
<p>Random number: {number}</p>
{:catch error}
<p style="color: red;">{error.message}</p>
{/await}
但如果刻意觸發錯誤,會發現根本沒有進到 {:catch}
,這是因為 error
設計上都是 return { message: string }
的物件,所以我們在外部 catch
不到它的,雖然我覺得這樣子反而更不方便使用就是了。
所以如果我們還是要在 +page.svelte
catch 到錯誤我們只能這麼做
const getRandomNumber = async ({ min, max }: { min: number; max: number }): Promise<number> => {
const response = await fetch(`/api/random-number?min=${min}&max=${max}`);
if (response.ok) {
return response.json();
}
const error = await response.json();
throw new Error(error.message);
};